package com.ywz.framework.mybatisplus;

import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.creator.DataSourceProperty;
import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.ywz.common.SymmetricAlgorithmUtils;
import com.ywz.framework.mybatisplus.mapper.DatabaseMapper;
import com.ywz.framework.property.MysqlTenementProperties;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import org.apache.ibatis.session.SqlSession;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.util.Objects;

/**
 * 类描述 -> 自定义动态数据源服务类
 *
 * @Author: ywz
 * @Date: 2024/11/17
 */
@Component
@AllArgsConstructor
public class MyDynamicDataSourceService {

    private final MysqlTenementProperties mysqlTenementProperties;
    @Resource
    private DataSource dataSource;
    @Resource
    private DefaultDataSourceCreator dataSourceCreator;

    /**
     * 方法描述 -> 创建数据库并初始化表
     *
     * @param key 数据源标识
     * @param tenementSimpleName 租户简称
     * @param url 数据源URL
     * @Author: ywz
     * @Date: 2024/11/17
     */
    public void initTable(String key,String tenementSimpleName, String url) {
        // 配置数据源
        DataSourceProperty dataSourceProperty = new DataSourceProperty();
        dataSourceProperty.setLazy(true);
        dataSourceProperty.setUsername(SymmetricAlgorithmUtils.decrypt(mysqlTenementProperties.username()));
        dataSourceProperty.setPassword(SymmetricAlgorithmUtils.decrypt(mysqlTenementProperties.password()));
        if (!url.contains(":"))
            url = url + ":3306"; // 使用默认端口号
        dataSourceProperty.setUrl("jdbc:mysql://" + url);
        dataSourceProperty.setDriverClassName(mysqlTenementProperties.driverClassName());
        // 创建sqlSessionFactory，配置mapper类
        MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
        MybatisConfiguration configuration = new MybatisConfiguration();
        configuration.addMapper(DatabaseMapper.class);
        sqlSessionFactoryBean.setConfiguration(configuration);
        sqlSessionFactoryBean.setDataSource(dataSourceCreator.createDataSource(dataSourceProperty));
        try {
            // 获取sqlSession
            SqlSession sqlSession = Objects.requireNonNull(sqlSessionFactoryBean.getObject()).openSession();
            DatabaseMapper mapper = sqlSession.getMapper(DatabaseMapper.class);
            // 初始化数据库
            mapper.createDatabase("`" + mysqlTenementProperties.databasePrefix() + key + "`");
            // 添加数据源到动态数据源
            DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
            dataSourceProperty.setUrl(dataSourceProperty.getUrl() + "/" + mysqlTenementProperties.databasePrefix() + key + mysqlTenementProperties.urlSuffix());
            DataSource dataSource1 = dataSourceCreator.createDataSource(dataSourceProperty);
            ds.addDataSource(key, dataSource1);
            // 初始化表
            ResourceDatabasePopulator popular = new ResourceDatabasePopulator();
            popular.addScript(new ClassPathResource(mysqlTenementProperties.initSql()));
            popular.execute(dataSource1);
            // 初始化管理员账户
            mapper.useDatabase("`" + mysqlTenementProperties.databasePrefix() + key + "`");
            String adminAccount = key + mysqlTenementProperties.adminName();
            BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
            mapper.saveAdminAccount(adminAccount, passwordEncoder.encode(mysqlTenementProperties.adminPassword()));
            mapper.saveAdminRole();
            mapper.saveAdminUserRole();
            // 添加租户标签
            mapper.saveTenementLabel(key, tenementSimpleName);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
